/*
 * $Id: UserServiceTestCase.java 42 2007-05-14 10:17:19Z aaron.day $
 */
package org.crazydays.core;


import java.util.*;

import org.apache.hivemind.Registry;
import org.apache.hivemind.impl.RegistryBuilder;

import org.hibernate.*;

import junit.framework.TestCase;

import org.crazydays.hibernate.HibernateUtil;
import org.crazydays.core.data.*;

/**
 * UserServiceTestCase
 */
public class UserServiceTestCase
	extends TestCase
{
	/** user service */
	private IUserService userService;

	/** list of users to cleanup */
	private List<PolisData> cleanupData = new LinkedList<PolisData>();

	/** session */
	private Session session;

	/**
	 * Setup test case.
	 */
	public void setUp()
	{
		// hivemind registry
		Registry registry = RegistryBuilder.constructDefaultRegistry();

		// user service
		userService = (IUserService) registry
				.getService(IUserService.class);
		assertNotNull("userService == null", userService);

		// hibernate 
		session = HibernateUtil.getSession();
		assertNotNull("session == null", session);
	}

	/**
	 * Teardown.
	 */
	public void tearDown()
	{
		Transaction transaction = null;

		// cleanup datas
		Iterator<PolisData> datas = cleanupData.iterator();
		while (datas.hasNext()) {
			PolisData data = datas.next();

			try {
				// begin transaction
				transaction = session.beginTransaction();

				// refresh data
				session.refresh(data);

				if (data instanceof PolisUser) {
					// delete user
					userService.deleteUser(session,
							(PolisUser) data);
				} else if (data instanceof PolisGroup) {
					// delete group
					userService.deleteGroup(session,
							(PolisGroup) data);
				} else if (data instanceof PolisAcl) {
					// delete acl
					userService.deleteAcl(session,
							(PolisAcl) data);
				} else {
					session.delete(data);
				}

				// commit transaction
				transaction.commit();
				transaction = null;
			} catch (DataException e) {
				transaction.rollback();
			} catch (HibernateException e) {
				if (transaction != null) {
					transaction.rollback();
				}
			}
		}

		// clear cleanup data
		cleanupData.clear();

		// cleanup session
		session.close();
	}

	/**
	 * Test createStandardUser.
	 */
	public void testCreateStandardUser()
	{
		assertNotNull("userService == null", userService);

		PolisUser user = newTestCaseUser();

		try {
			user = userService.createStandardUser(user);

			assertNotNull("user == null", user);
			assertNotSame("user.id == 0", user.getId(), 0);
			assertTestCaseUser(user);

			cleanupData.add(user);
		} catch (DataException e) {
			fail("DataException: " + e.getMessage());
		}
	}

	/**
	 * Test loadUser(), saveUser(), deleteUser().
	 */
	public void testUserFunctions()
	{
		assertNotNull("userService == null", userService);
		assertNotNull("session == null", session);

		Transaction transaction = null;

		try {
			// begin transaction
			transaction = session.beginTransaction();

			PolisUser user = null;

			// attempt to load user
			user = userService.loadUser(session, TEST_USER_NAME);
			assertNull("user != null", user);

			// create new user
			user = newTestCaseUser();

			// save user
			user = userService.saveUser(session, user);
			assertNotNull("user == null");
			assertNotSame("user.id == 0", user.getId(), 0);

			// add user to cleanup list
			cleanupData.add(user);

			// begin transaction
			transaction.commit();

			// begin transaction
			transaction = session.beginTransaction();

			// verify user created
			user = userService.loadUser(session, TEST_USER_NAME);
			assertNotNull("user == null", user);
			assertNotSame("user.id == 0", user.getId(), 0);

			// remove user from cleanup list
			cleanupData.remove(user);

			// delete user
			userService.deleteUser(session, user);

			// commit transaction
			transaction.commit();

			// begin transaction
			transaction = session.beginTransaction();

			// verify user deleted
			user = userService.loadUser(session, TEST_USER_NAME);
			assertNull("user != null", user);

			// commit transaction
			transaction.commit();

		} catch (DataException e) {
			transaction.rollback();
			fail("DataException: " + e.getMessage());
		} catch (HibernateException e) {
			if (transaction != null) {
				transaction.rollback();
			}
			fail("DataException: " + e.getMessage());
		}

	}

	/**
	 * Test loadGroup(), saveGroup(), deleteGroup().
	 */
	public void testGroupFunctions()
	{
		assertNotNull("userService == null", userService);
		assertNotNull("session == null", session);

		PolisUser user = newTestCaseUser();
		PolisGroup group = null;
		Transaction transaction = null;

		try {
			// begin transaction
			transaction = session.beginTransaction();

			// attempt to load group
			group = userService.loadGroup(session, TEST_GROUP_NAME);
			assertNull("group != null", group);

			// create user
			user = userService.saveUser(session, user);

			// add user to cleanup
			cleanupData.add(user);

			// create group
			group = newTestCaseGroup(user);

			// save group
			group = userService.saveGroup(session, group);
			assertNotSame("group.id == 0", group.getId(), 0);

			// add group to cleanup
			cleanupData.add(group);

			// commit transaction
			transaction.commit();

			// begin transaction
			transaction = session.beginTransaction();

			// load group
			group = userService.loadGroup(session, TEST_GROUP_NAME);
			assertNotNull("group == null", group);
			assertNotSame("group.id == 0", group.getId(), 0);

			// verify
			assertTestCaseGroup(group, user);
			assertEquals("group.users.size != 1", group.getUsers()
					.size(), 1);
			assertEquals("group.users(0) != user", group.getUsers()
					.toArray()[0], user);

			// delete group
			group = userService.deleteGroup(session, group);
			assertNotNull("group == null", group);

			// remove group from cleanup list
			cleanupData.remove(group);

			// commit transaction
			transaction.commit();

			// begin transaction
			transaction = session.beginTransaction();

			// load group
			group = userService.loadGroup(session, TEST_GROUP_NAME);
			assertNull("group != null", group);

			// commit transaction
			transaction.commit();
		} catch (DataException e) {
			transaction.rollback();
			fail("DataException: " + e.getMessage());
		} catch (HibernateException e) {
			if (transaction != null) {
				transaction.rollback();
			}
			fail("DataException: " + e.getMessage());
		}
	}

	/**
	 * Test loadAcl, saveAcl, deleteAcl functions.
	 */
	public void testAclFunctions()
	{
		assertNotNull("userService == null", userService);
		assertNotNull("session == null", session);

		PolisUser user = null;
		PolisGroup group = null;
		PolisAcl acl = null;

		Transaction transaction = null;

		try {
			// begin transaction
			transaction = session.beginTransaction();

			// create user
			user = newTestCaseUser();
			user = userService.saveUser(session, user);
			assertNotNull("user == null", user);
			assertNotSame("user.id == 0", user.getId(), 0);
			assertTestCaseUser(user);
			cleanupData.add(user);

			// create group
			group = newTestCaseGroup(user);
			group = userService.saveGroup(session, group);
			assertNotNull("group == null", group);
			assertNotSame("group.id == 0", group.getId(), 0);
			assertTestCaseGroup(group, user);
			cleanupData.add(group);

			// load acl (non exist)
			acl = userService.loadAcl(session, TEST_ACL_NAME);
			assertNull("acll != null", acl);

			// test saveAcl
			acl = newTestCaseAcl(user);
			acl = userService.saveAcl(session, acl);
			assertNotNull("acl == null", acl);
			assertNotSame("acl.id == 0", acl.getId(), 0);
			assertTestCaseAcl(acl, user);

			// commit transaction
			transaction.commit();

			// begin transaction
			transaction = session.beginTransaction();

			// test loadAcl
			acl = userService.loadAcl(session, TEST_ACL_NAME);
			assertNotNull("acl == null", acl);
			assertNotSame("acl.id == 0", acl.getId(), 0);
			assertTestCaseAcl(acl, user);
			cleanupData.remove(acl);

			// test deleteAcl
			acl = userService.deleteAcl(session, acl);

			// commit transaction
			transaction.commit();

			// begin transaction
			transaction = session.beginTransaction();

			// verify deletion
			acl = userService.loadAcl(session, TEST_ACL_NAME);
			assertNull("acl != null", acl);

			// commit transaction
			transaction.commit();
		} catch (DataException e) {
			transaction.rollback();
			fail("DataException: " + e.getMessage());
		} catch (HibernateException e) {
			if (transaction != null) {
				transaction.rollback();
			}
			fail("DataException: " + e.getMessage());
		}
	}

	/** test user: name */
	private final static String TEST_USER_NAME = "TestCaseUserName";

	/** test user: description */
	private final static String TEST_USER_DESCRIPTION = "TestCase User Description";

	/** test user: summary */
	private final static String TEST_USER_SUMMARY = "TestCase User";

	/** test user: username */
	private final static String TEST_USER_USERNAME = "TestCaseUser";

	/** test user: password */
	private final static String TEST_USER_PASSWORD = "TestCaseUserPassword";

	/** test user: email */
	private final static String TEST_USER_EMAIL = "TestCaseUser@TestCase.Foo";

	/**
	 * Create new polis user.
	 * 
	 * @return User
	 */
	private PolisUser newTestCaseUser()
	{
		PolisUser user = new PolisUser();
		user.setName(TEST_USER_NAME);
		user.setDescription(TEST_USER_DESCRIPTION);
		user.setSummary(TEST_USER_SUMMARY);
		user.setUsername(TEST_USER_USERNAME);
		user.setPassword(TEST_USER_PASSWORD);
		user.setEmail(TEST_USER_EMAIL);
		return user;
	}

	/**
	 * Assert test case user matches user created from newTestCaseUser().
	 * 
	 * @param user User
	 */
	private void assertTestCaseUser(PolisUser user)
	{
		assertNotNull("user == null", user);
		assertEquals("user.name != " + TEST_USER_NAME, user.getName(),
				TEST_USER_NAME);
		assertEquals("user.description != " + TEST_USER_DESCRIPTION,
				user.getDescription(), TEST_USER_DESCRIPTION);
		assertEquals("user.summary != " + TEST_USER_SUMMARY, user
				.getSummary(), TEST_USER_SUMMARY);
		assertEquals("user.username != " + TEST_USER_USERNAME, user
				.getUsername(), TEST_USER_USERNAME);
		assertEquals("user.password != " + TEST_USER_PASSWORD, user
				.getPassword(), TEST_USER_PASSWORD);
		assertEquals("user.email != " + TEST_USER_EMAIL, user
				.getEmail(), TEST_USER_EMAIL);
	}

	/** test group: name */
	private final static String TEST_GROUP_NAME = "TestCaseGroupName";

	/** test group: description */
	private final static String TEST_GROUP_DESCRIPTION = "Test Case Group Description";

	/** test group: summary */
	private final static String TEST_GROUP_SUMMARY = "TestCase Group";

	/**
	 * Create test group.
	 * 
	 * @return Group
	 */
	private PolisGroup newTestCaseGroup(PolisUser user)
	{
		// setup basic group
		PolisGroup group = new PolisGroup();
		group.setName(TEST_GROUP_NAME);
		group.setDescription(TEST_GROUP_DESCRIPTION);
		group.setSummary(TEST_GROUP_SUMMARY);

		// add user to group
		group.setUser(user);
		group.getUsers().add(user);

		return group;
	}

	/**
	 * Assert test case group matches group created from newTestCaseGroup().
	 * 
	 * @param group Group
	 * @param user User
	 */
	private void assertTestCaseGroup(PolisGroup group, PolisUser user)
	{
		assertNotNull("group == null", group);
		assertEquals("group.name != " + TEST_GROUP_NAME, group
				.getName(), TEST_GROUP_NAME);
		assertEquals("group.description != " + TEST_GROUP_DESCRIPTION,
				group.getDescription(), TEST_GROUP_DESCRIPTION);
		assertEquals("group.summary != " + TEST_GROUP_SUMMARY, group
				.getSummary(), TEST_GROUP_SUMMARY);

		// user
		assertNotNull("user == null", user);
		assertNotNull("group.user == null", group.getUser());
		assertEquals("group.user != " + user, group.getUser(), user);
		assertNotNull("group.users == null", group.getUsers());
		assertTrue("!group.users.contains " + user, group.getUsers()
				.contains(user));
	}

	/** test acl: name */
	private final static String TEST_ACL_NAME = "TestCaseACLName";

	/** test acl: description */
	private final static String TEST_ACL_DESCRIPTION = "TestCase Acl Description";

	/** test acl: summary */
	private final static String TEST_ACL_SUMMARY = "TestCase Acl";

	/**
	 * Create test case acl.
	 * 
	 * @param user User
	 * @return Acl
	 */
	private PolisAcl newTestCaseAcl(PolisUser user)
	{
		PolisAcl acl = new PolisAcl();

		// setup acl
		acl.setName(TEST_ACL_NAME);
		acl.setDescription(TEST_ACL_DESCRIPTION);
		acl.setSummary(TEST_ACL_SUMMARY);

		// user
		acl.setUser(user);

		return acl;
	}

	/**
	 * Assert test case acl matches acl created from newTestCaseAcl().
	 * 
	 * @param acl Acl
	 * @param user User
	 */
	private void assertTestCaseAcl(PolisAcl acl, PolisUser user)
	{
		assertNotNull("acl == null", acl);
		assertEquals("acl.name != " + TEST_ACL_NAME, acl.getName(),
				TEST_ACL_NAME);
		assertEquals("acl.description != " + TEST_ACL_DESCRIPTION, acl
				.getDescription(), TEST_ACL_DESCRIPTION);
		assertEquals("acl.summary != " + TEST_ACL_SUMMARY, acl
				.getSummary(), TEST_ACL_SUMMARY);

		assertNotNull("user == nul", user);
		assertEquals("acl.user != " + user, acl.getUser(), user);
	}
}
